package com.zoweunion.mechanic.util.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zoweunion.mechanic.dao.FacilitatorPersonnelRelationDao;
import com.zoweunion.mechanic.dao.TSSsVehicleBrandParentDao;
import com.zoweunion.mechanic.dao.app.ToolCarDataMapper;
import com.zoweunion.mechanic.entity.LocateInfo;
import com.zoweunion.mechanic.entity.Point;
import com.zoweunion.mechanic.model.SmsSendRequest;
import com.zoweunion.mechanic.plugins.redis.RedisUtil;
import com.zoweunion.mechanic.service.app.ToolCarDataService;
import com.zoweunion.mechanic.service.base.LockCarService;
import com.zoweunion.mechanic.util.*;
import com.zoweunion.mechanic.util.constants.Constants;
import com.zoweunion.mechanic.util.gaode.AddressGEOUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ExecutorService;

import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.ExecutorService;
import javax.annotation.Resource;

import static com.zoweunion.mechanic.netty.DiscardServerHandler.map;


/**
 * 车辆定位精度优化
 */

@Component
public class CarPositioningAccuracyTask {

    @Autowired
    private ToolCarDataMapper toolCarDataMapper;

    @Autowired
    private ToolCarDataService toolCarDataService;

    @Autowired
    private AddressGEOUtil addressGEOUtil;
    @Autowired
    private Environment env;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private FacilitatorPersonnelRelationDao facilitatorPersonnelRelationDao;

    @Resource(name = "cachedThreadPool")
    private ExecutorService executorService;

    @Autowired
    private TSSsVehicleBrandParentDao tsssVehicleBrandParentDao;

    @Autowired
    private RedisUtil redisUtil;

    public static final String things_info = "_things_info";


    // 车辆在线的数据更新
    @Scheduled(cron = "0 0/4 * * * ?")
    public void carOnlineAccuracy() {

        ArrayList<Map<String, Object>> thingsList = toolCarDataMapper.getAllTodayOnlineThings();

        System.out.println("物联网关GPS更新数组：" + thingsList);

        thingsList.forEach(thingsMap -> {

            String thingsId = thingsMap.get("things_id").toString();

            // 铝壳版的判断
            if (Constants.is18Or19(thingsId)) {

                return;
            }
            try {

                //executorService.execute(() -> {
                this.calculateLocation(thingsId);
                //});

            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    // 设备在线的数据更新
    @Scheduled(cron = "0 0/3 * * * ?")
    public void deviceOnlineAccuracy() {

        ArrayList<Map<String, Object>> thingsList = toolCarDataMapper.getAllTodayDeviceOnlineThings();

        System.out.println("物联网关GPS更新数组：" + thingsList);

        thingsList.forEach(thingsMap -> {

            String thingsId = thingsMap.get("things_id").toString();

            // 铝壳版的判断
            if (Constants.is18Or19(thingsId)) {

                return;
            }
            try {
                this.calculateLocation(thingsId);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    // 设备在线的数据更新
    @Scheduled(cron = "0 0/20 * * * ?")
    public void updateGPSLocation() {

        ArrayList<Map<String, Object>> thingsList = toolCarDataMapper.getAllDeviceOnlineThings();

        thingsList.forEach(item -> {

            try {
                String things_id = item.get("things_id").toString();

                // TODO 20分钟刷新一次所有盒子的在线的设备，更新经纬度和地理位置
                // 改进方案，放到MQDataAlarmPush里面，新来的数据转为地理位置和real表的数据比对，有变化就更新，没变化不更新
                this.thingsGPSCityData(item,things_id);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    // 设备在线的数据更新 更新redis的数据
    @Scheduled(cron = "0 0/1 * * * ?")
    public void updateRedis170DataInfo() {

        if (!redisUtil.exists("redis-test")) {

            redisUtil.insertSetForString("redis-Ok","redis-test");
        }

        List<String> strings = facilitatorPersonnelRelationDao.selectServer();

        strings.forEach(item -> {

            executorService.execute(()-> {
                //删除redis
                redisUtil.remove(item + things_info);
                //插入redis
                List<Map<String, Object>> list = facilitatorPersonnelRelationDao.selectCarInfo(item);
                if (list != null) {
                    if(redisUtil.exists("item + things_info")){

                        redisUtil.insertList(list, item + things_info);
                    }
                }
            });
        });
    }

    // 更新经纬度城市的数据
    private void thingsGPSCityData(Map<String,Object> locationMap, String things_id) {

        if (locationMap != null) {

            if (locationMap.get(Constants.THINGS_GPSlatitude) != null) {

                // 查找实时数据
                Map<String, Object> realMap = toolCarDataMapper.selectRedisRealDataByThingsId(things_id);

                String longitude = locationMap.get(Constants.THINGS_GPSlongitude).toString();
                String latitude = locationMap.get(Constants.THINGS_GPSlatitude).toString();

                realMap.put("GPSlongitude",longitude);
                realMap.put("GPSlatitude",latitude);
                realMap.put("thingsId",things_id);

                JSONObject region = addressGEOUtil.getRegion(longitude, latitude);

                String city = region.getString("city");
                String province = region.getString("province");

                if (region.get("city").toString().equals("[]")) {

                    city = province;
                }

                // TODO 以下方法只有地理位置变化才会执行
                Map<String, Object> provinceMap = toolCarDataMapper.getCode(province);
                String provinceCode = provinceMap.get("Id").toString();
                String ParentId = provinceMap.get("ParentId").toString();
                if (!ParentId.equals("100000")) {

                    provinceCode = ParentId;
                }

                Map<String, Object> cityMap = toolCarDataMapper.getCode(city);

                String cityCode = cityMap.get("Id").toString();

                realMap.put("province",province);
                realMap.put("city",city);
                realMap.put("district",region.getString("district"));
                realMap.put("province_code",provinceCode);
                realMap.put("city_code",cityCode);
                realMap.put("district_code",region.getString("adcode"));

                toolCarDataMapper.updateDataReal(realMap);
            }
        }
    }

    // 170数据的计算
    private void calculateLocation(String thingsId) {

        String intelligentId = "";

        String date = DateUtil.formatDate(LocalDate.now());

        System.out.println("物联网关GPS开始更新：" + thingsId);

        Map<String, Object> lastLocation = toolCarDataService.getDataStatisticsObj(thingsId, intelligentId, date);

        if (lastLocation.get(Constants.THINGS_GPSlatitude) != null) {

            Double latitude = Double.parseDouble(lastLocation.get(Constants.THINGS_GPSlatitude).toString());
            Double longitude = Double.parseDouble(lastLocation.get(Constants.THINGS_GPSlongitude).toString());

            Map<String, Object> convertLocation = addressGEOUtil.gaodeConvertGPS(longitude,latitude);

            Map<String, Object> recordMap = new HashMap<>();

            if (convertLocation.get("infocode").toString().equals("10000")) {

                String[] arr = convertLocation.get("locations").toString().split(",");

                recordMap.put(Constants.THINGS_GPSlongitude, arr[0]);
                recordMap.put(Constants.THINGS_GPSlatitude, arr[1]);

            }else {

                LocateInfo locateInfo = Point.wgs84_To_Gcj02(latitude, longitude);
                recordMap.put(Constants.THINGS_GPSlongitude, locateInfo.getLongitude());
                recordMap.put(Constants.THINGS_GPSlatitude, locateInfo.getLatitude());
            }

            recordMap.put("thingsId", thingsId);

            toolCarDataMapper.insertLocationRecord(recordMap);

            toolCarDataMapper.insertcarLocationData(recordMap);

            Map<String,Object> dataByThingsId = toolCarDataMapper.selectDataByThingsId(thingsId);
            if (dataByThingsId == null) {
                toolCarDataMapper.insertDataReal(recordMap);
            } else {
                toolCarDataMapper.updateDataReal(recordMap);
            }

            toolCarDataMapper.insertLocationRecord(recordMap);

            try {

                String[] activeProfiles = env.getActiveProfiles();
                String activeProfile = activeProfiles[0];
                if (activeProfile.equals("prod")){
                    activeProfile="DIS";
                }else if (activeProfile.equals("dev")){
                    activeProfile="DEV";
                }

                String gaodeThingsId = activeProfile+thingsId;

                // 高德经纬度
//                    toolCarDataMapper.insertLocationTemp(recordMap);//临时表插入经纬度
                //todo
                Map<String, Object> map = addressGEOUtil.terminalList(gaodeThingsId);

                int tid=0;
                int trid=0;

                if (map.get("data")==null){//判断是否有值 没有则新建
                    Map<String, Object> terminalAdd = addressGEOUtil.terminalAdd(gaodeThingsId);
                    Map parseObject = JSON.parseObject(terminalAdd.get("data").toString(), Map.class);
                    tid=Integer.valueOf(parseObject.get("tid").toString());
                    //创建轨迹
                    Map<String, Object> traceAdd = addressGEOUtil.terminalTraceAdd(tid);
                    Map parseObject1 = JSON.parseObject(traceAdd.get("data").toString(), Map.class);
                    trid=Integer.valueOf(parseObject1.get("trid").toString());
                    //插入轨迹
                    toolCarDataMapper.insertTrid(gaodeThingsId,tid,trid, UuidUtil.get32UUID());
                }else {
                    Map<String, Object> selectTrid = toolCarDataMapper.selectTrid(gaodeThingsId);

                    if (selectTrid != null) {
                        trid= Integer.valueOf(selectTrid.get("trid").toString());
                        tid= Integer.valueOf(selectTrid.get("tid").toString());
                    }
                }

                // 查询临时表经纬度
                List<Map<String, Object>> arrayList = new ArrayList<>();
                Map<String, Object> map1 = new HashMap<>();
                map1.put("location", recordMap.get(Constants.THINGS_GPSlongitude)+","
                        + recordMap.get(Constants.THINGS_GPSlatitude));
                map1.put("locatetime",new Date().getTime());
                arrayList.add(map1);
                if (tid != 0 && trid != 0) {
                    JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(arrayList));
                    addressGEOUtil.tracePointAdd(tid,trid,jsonArray);//插入轨迹id
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        toolCarDataMapper.updateDataStatistics(lastLocation);
    }

    // 注册高德的轨迹
    @Scheduled(cron = "0 0 4 1/1 * ?")
    public void registerGaodeTid() {

        // TODO 高德地图的注册，用高德地图的API判断有没有注册高德地图，没有注册的话就注册，放到MQDataAlarmPush判断
        ArrayList<Map<String, Object>> thingsList = toolCarDataMapper.selectAllRealThingsId();

        thingsList.forEach(thingsMap -> {

            String thingsId = thingsMap.get("things_id").toString();

            try {

                String[] activeProfiles = env.getActiveProfiles();
                String activeProfile = activeProfiles[0];
                if (activeProfile.equals("prod")){
                    activeProfile="DIS";
                }else if (activeProfile.equals("dev")){
                    activeProfile="DEV";
                }

                String gaodeThingsId = activeProfile+thingsId;

                // 高德经纬度
                //todo
                Map<String, Object> map = addressGEOUtil.terminalList(gaodeThingsId);

                int tid=0;
                int trid=0;

                if (map.get("data")==null){//判断是否有值 没有则新建
                    Map<String, Object> terminalAdd = addressGEOUtil.terminalAdd(gaodeThingsId);
                    Map parseObject = JSON.parseObject(terminalAdd.get("data").toString(), Map.class);
                    tid=Integer.valueOf(parseObject.get("tid").toString());
                    //创建轨迹
                    Map<String, Object> traceAdd = addressGEOUtil.terminalTraceAdd(tid);
                    Map parseObject1 = JSON.parseObject(traceAdd.get("data").toString(), Map.class);
                    trid=Integer.valueOf(parseObject1.get("trid").toString());
                    //插入轨迹
                    toolCarDataMapper.insertTrid(gaodeThingsId,tid,trid, UuidUtil.get32UUID());
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    // 更新状态
    @Scheduled(cron = "0 0/1 * * * ?")
    public void updateCarStatus() {

        ArrayList<Map<String, Object>> onlineThings = toolCarDataMapper.getAllOnlineThingsNew();

        onlineThings.forEach(item -> {

            String thingsId = item.get("things_id").toString();

//            Map<String, Object> realTemplateMap = toolCarDataMapper.getCarRealTemplateData(thingsId);
//
//            if (realTemplateMap == null) {
//
//                return;
//            }

            int status = 2;//车辆默认为离线状态
            int deviceStatus = 2;
            int fault_status = 2; // 故障状态

            if (item.get(Constants.THINGS_IsCAT) == null) {

                item.put(Constants.THINGS_IsCAT,2.0);
            }

            if (item.get(Constants.THINGS_Ignition) == null) {

                item.put(Constants.THINGS_Ignition,"0");
            }

            if (item.get(Constants.THINGS_RotateSpeed) == null) {

                item.put(Constants.THINGS_RotateSpeed,"0");
            }

            if (item.get(Constants.THINGS_EngineTotalHours) == null) {

                item.put(Constants.THINGS_EngineTotalHours,"0");
            }

            //有点火 并且大于10 ,有转速视为上线
            if ((Double.valueOf(item.get(Constants.THINGS_Ignition).toString()) > 10) || (Double.valueOf(item.get(Constants.THINGS_RotateSpeed).toString()) > 0)) {
                status = 1;
                deviceStatus = 1;
            }

//            String sid = toolCarDataMapper.selectSidByThingsId(thingsId);
//
//            // 如果是子服务商，则查询出来父主机厂的sid
//            String p_id =  tsssVehicleBrandParentDao.getPServerIdByServerId(sid);
//
//            if (!p_id.isEmpty()) {
//
//                sid = p_id;
//            }
//
//            if (!sid.isEmpty() && sid.equals(Constants.hdznSId)) {
//
//                Date time = null;
//                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//                try {
//                    time = simpleDateFormat.parse(item.get("sample_time").toString());
//                } catch (ParseException e) {
//                    e.printStackTrace();
//                }
//
//                if ((new Date().getTime() - time.getTime()) < 5 * 60 * 1000) {
//                    status = 1;
//                    deviceStatus = 1;
//                }
//            }

            // 在线设备判断时间维度
            if (status == 1) {

                Date time = null;
                SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    time = simpleDateFormat.parse(item.get("sample_time").toString());
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                if ((new Date().getTime() - time.getTime()) > 5 * 60 * 1000) {
                    status = 2;
                }
            }

            Date dateTime = null;
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                dateTime = simpleDateFormat.parse(item.get("sample_time").toString());
            } catch (ParseException e) {
                e.printStackTrace();
            }
            //判断设备是否离线
            if ((new Date().getTime() - dateTime.getTime()) > 5 * 60 * 1000) {
                deviceStatus = 2;
                status = 2;
            }

            Map<String, Object> tempMap = new HashMap<>();

            tempMap.put("thingsId",thingsId);
            tempMap.put("deviceStatus",deviceStatus);

            // 先判断状态
            if (item.get("status") != null) {

                // 目前判断为开机，上一次状态是关机
                if (status == 1 && item.get("status").toString().equals("2")) {

                    tempMap.put("open_status",true);
                }

                if (status == 2 && item.get("status").toString().equals("1")) {

                    tempMap.put("open_status",false);
                }

            }else {

                if (status == 1) {

                    tempMap.put("open_status",true);
                }else if (status == 2) {

                    tempMap.put("open_status",false);
                }
            }

            //判断是否故障
            Integer faultCount = toolCarDataMapper.countRealFaultCodeDataToday(thingsId);
            if (faultCount > 0) {
                fault_status = 1;
            }else {

                fault_status = 2;
            }

            tempMap.put("status",status);
            tempMap.put("fault_status",fault_status);

            // 记录每天的第一次开机时间，如果已经记录了开机时间的话，就不插入数据了
            try {

                if (tempMap.get("open_status").equals(true)) {

                    String start_time = item.get("start_time").toString();

                    SimpleDateFormat simpleDateFormatyyyy = new SimpleDateFormat("yyyy-MM-dd");
                    String nowDateString = simpleDateFormatyyyy.format(new Date());

                    Date startDate = simpleDateFormatyyyy.parse(start_time);

                    String startDateString = simpleDateFormatyyyy.format(startDate);

                    if (nowDateString.equals(startDateString)) {

                        tempMap.put("open_status",false);
                    }else {

                        ArrayList<String> tempList = new ArrayList<>();

                        tempList.add(item.get(Constants.THINGS_GPSlongitude).toString());
                        tempList.add(item.get(Constants.THINGS_GPSlatitude).toString());
                    }
                }

            } catch (Exception ignored) {}

            toolCarDataMapper.updateByStatus(tempMap);
        });
    }

    // 每天凌晨4点，查询有故障的设备，更新一下故障代码的状态
    @Scheduled(cron = "0 0 4 1/1 * ?")
    public void updateCarFaultStatus() {

        ArrayList<Map<String, Object>> onlineThings = toolCarDataMapper.getAllFaultThings();

        onlineThings.forEach(item -> {

            String thingsId = item.get("things_id").toString();
            int fault_status = 2; // 故障状态
            Map<String, Object> tempMap = new HashMap<>();

            //判断是否故障
            Integer faultCount = toolCarDataMapper.countRealFaultCodeDataToday(thingsId);
            if (faultCount > 0) {
                fault_status = 1;
            }else {

                fault_status = 2;
            }

            tempMap.put("fault_status",fault_status);
            tempMap.put("thingsId",thingsId);

            toolCarDataMapper.updateByFaultStatus(tempMap);
        });
    }

    // 更新状态
    @Scheduled(cron = "0 0/5 * * * ?")
    public void redisInsertForCAT() {

        //redis：key：CATOnlineThings_20201015
        SimpleDateFormat simpleDateFormatyyyy = new SimpleDateFormat("yyyyMMdd");

        String nowDateString = simpleDateFormatyyyy.format(new Date());

        String redisKey = Constants.CATOnlineThings + nowDateString;

        ArrayList<Map<String, Object>> catOnlineThings = toolCarDataMapper.getCATOnlineThingsId(Constants.catSId);

        // redis 存储每天卡特在线的设备
        catOnlineThings.forEach(item -> {

            String things_id = item.get("things_id").toString();

            if (redisUtil.exists(redisKey)) {

                List<String> redisArray = redisUtil.getListForString(redisKey);

                if (!redisArray.contains(things_id)) {

                    redisUtil.insertListForString(things_id,redisKey);
                }
            }else {

                redisUtil.insertListForString(things_id,redisKey);
            }
        });

        //模拟量
        String redisKey1 = Constants.CATMoNiThings + nowDateString;

        ArrayList<Map<String, Object>> catOnlineThings1 = toolCarDataMapper.getCATOnlineThingsId(Constants.catMoNiSId);


        catOnlineThings1.forEach(item -> {

            String things_id = item.get("things_id").toString();

            if (redisUtil.exists(redisKey1)) {

                List<String> redisArray = redisUtil.getListForString(redisKey1);

                if (!redisArray.contains(things_id)) {

                    redisUtil.insertListForString(things_id,redisKey1);
                }
            }else {

                redisUtil.insertListForString(things_id,redisKey1);
            }
        });
    }

    //通过thingsid获取表名
    private String selectTableByThingsId(String thingsId){
        Map<String, Object> map1 = toolCarDataMapper.selectByThingsId(thingsId);

        String tableName = "pc_car_";
        Calendar calendar = Calendar.getInstance();
        calendar.setFirstDayOfWeek(Calendar.MONDAY);
        calendar.setTime(new Date());
        int weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR);
        int year = calendar.get(Calendar.YEAR);

        String bsd = "";
        tableName = tableName + "other_" + year + "_W" + weekOfYear;

        if (map1 != null) {

            if (map1.containsKey("s_id")) {

                if (map1.get("s_id") != null) {

                    bsd = map1.get("bsd").toString();

                    tableName = "pc_car_";
                    tableName = tableName + bsd.substring(bsd.length() - 6, bsd.length())
                            + "_" + year + "_W" + weekOfYear;
                }
            }
        }

        return tableName;
    }

    private static Logger logger = LoggerFactory.getLogger(SmsUtil.class);
    private static LockCarService lockCarService = SpringUtils.getBean(LockCarService.class);
    public static String sendSms(String phoneNum, String content) {
        Map<String, Object> smsMap = lockCarService.getSmsSendTotalByPhone(phoneNum);
        if (smsMap == null) {
            lockCarService.initSendRecordNumber(phoneNum);
        } else {
            lockCarService.updateSendTotalByPhone(phoneNum);
            int sendTotal = Integer.valueOf(smsMap.get("sendTotal").toString());
            String type = smsMap.get("type").toString();
            if ("1".equals(type)) {
                if (sendTotal > 50) {
                    logger.error("短信发送失败，原因：达到今日上线次数");

                    return "达到今日上线次数";
                }
            }
        }
        SmsSendRequest smsSingleRequest = new SmsSendRequest(Constants.SMS_UID, Constants.SMS_KEY, content, phoneNum);
        String requestJson = JSON.toJSONString(smsSingleRequest);
        String result = SendMsg.sendSmsByPost(requestJson);
        Map<String, Object> resultMap = JSONObject.parseObject(result, Map.class);
        if (!resultMap.get("code").equals("0")) {
            logger.error("短信发送失败，原因：" + resultMap.get("errorMsg").toString());
            return resultMap.get("errorMsg").toString();
        }
        return "";
    }
}